/*
 * World.h
 *
 *  Created on: May 17, 2011
 *      Author: madboyka
 */

#ifndef WORLD_H_
#define WORLD_H_

#include "Server.h"
#include "ViewerWorker.h"
#include <QVector>
#include <QMutex>
#include "Robot.h"
#include "RobotFactory.h"
#include "Obstacle.h"
#include "ObstacleFactory.h"
#include "pal/palFactory.h"
#include "pal/ConfigStatic.h"

class Server;
class ViewerWorker;

/*!
 * The World class holds the physical world and runs the simulation.
 */
class World
{
private:
	float simulationStep; // 60fps
	QVector<Robot*> robots;
	QVector<Obstacle*> obstacles;
	QVector<ElementData> elements;
	palPhysics *physics;
	Server *server;
	RobotFactory *robotFactory;
	ObstacleFactory *obstacleFactory;
	QMutex elementsMutex;
	bool simulationRunning;
	bool initialized;
public:
	World();
	virtual ~World();
	/*!
	 * Initializes the simulation world, loading the specified map.
	 */
	void init(Server*);
	/*!
	 * Start the simulation.
	 */
	void startSimulation();
	/*!
	 * Pause the simulation.
	 */
	void pauseSimulation();
	/*!
	 * Return true if simulation is currently running.
	 */
	bool isSimulationRunning();
	/*!
	 * Steps the simulation with the predefined time step.
	 */
	void stepSimulation();
	/*!
	 * Return the time spent on simulation.
	 */
	float getSimulationTime();
	/*!
	 * Returns the time stem for the simulation.
	 */
	float getStepTime();
	/*!
	 * To be implemented...
	 */
	void reset();
	/*!
	 *  Main simulation loop, that is run in a thread.
	 */
	void run();
	/*!
	 * Adds an obstacle to the world pool, and returns the created obstacle.
	 * activateObstacle may be called after, to create its physics.
	 */
	Obstacle* addObstacle(const char*);
	/*!
	 * Returns an obstacle from the world pool designated by the index.
	 */
	Obstacle* getObstacle(int id);
	/*!
	 * Activates the given obstacle, placing it in the physical simulation.
	 */
	void activateObstacle(Obstacle*);
	/*!
		 * Adds a robot to the world pool, and returns the created robot.
		 * activateRobot may be called after, to create its physics.
		 */
	Robot* addRobot(const char*);
	/*!
		 * Returns a robot from the world pool designated by the index.
		 */
	Robot* getRobot(int id);
	/*!
	 * Activates the given obstacle, placing it in the physical simulation.
	 */
	void activateRobot(Robot*);
	/*!
	 * Loads the element locations from the obstacles and robots in the world pool.
	 */
	void loadLocations(WorldObject*);
	/*!
	 * Initializes a viewer, by sending all the elements.
	 */
	void initializeViewer(ViewerWorker*);
	/*!
	 * Locker method for accessing the elements.
	 */
	void requestElementsAccess();
	/*!
	 * Unlocker method for releasing the elements.
	 */
	void restoreElementsAccess();

	friend class ViewerWorker;
};

#endif /* WORLD_H_ */
